package com.haredot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.haredot.constraint.RedisConst;
import com.haredot.constraint.SolrConst;
import com.haredot.dto.AuditeDTO;
import com.haredot.dto.ResourceDTO;
import com.haredot.dto.ResourceSolrDTO;
import com.haredot.entity.Notify;
import com.haredot.entity.Resource;
import com.haredot.entity.ScoreConfig;
import com.haredot.entity.UserScore;
import com.haredot.event.RssNotifyEvent;
import com.haredot.event.enums.NotifyType;
import com.haredot.mapper.ResourceMapper;
import com.haredot.mapper.ScoreConfigMapper;
import com.haredot.mapper.UserScoreMapper;
import com.haredot.service.ResourceService;
import com.haredot.vo.R;
import com.haredot.vo.ResourceViewVo;
import com.haredot.vo.ResourceVo;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.solr.core.SolrTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @author Administrator
 * @description 针对表【tb_resource】的数据库操作Service实现
 * @createDate 2023-09-02 21:56:27
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, Resource> implements ResourceService {

    @javax.annotation.Resource
    private UserScoreMapper userScoreMapper;

    @javax.annotation.Resource
    private ScoreConfigMapper scoreConfigMapper;


    @javax.annotation.Resource
    private RedisTemplate<String, ResourceViewVo> redisTemplate ;

    @javax.annotation.Resource
    private SolrTemplate solrTemplate ;

    @javax.annotation.Resource
    private ApplicationEventPublisher applicationEventPublisher ;
    /**
     * 按照条件查询所有资源信息
     *
     * @param pageVo
     * @param resourceDTO
     */
    @Override
    public Page<ResourceVo> queryResourcesByCondition(Page<ResourceVo> pageVo, ResourceDTO resourceDTO) {

        return this.getBaseMapper().findResourcesByCondition(pageVo, resourceDTO);
    }

    @Override
    public R<?> auditeResource(AuditeDTO auditeDTO) {
        // 根据资源ID, 查询资源信息
        Resource resource = this.getBaseMapper().selectById(auditeDTO.getId());

        Assert.notNull(resource, "资源信息不存在");

        UpdateWrapper<Resource> resourceUpdateWrapper = new UpdateWrapper<Resource>()
                .set("state", auditeDTO.getState())
                .set(auditeDTO.getReason() != null, "reason", auditeDTO.getReason())
                .set("user", SecurityContextHolder.getContext().getAuthentication().getName())
                .set("update_time", LocalDateTime.now())
                .eq("id", auditeDTO.getId());

        int len = this.getBaseMapper().update(null, resourceUpdateWrapper);

        // 如果资源通过，则赠送积分
        if (len == 1 && auditeDTO.getState() == 1) {
            final String action = "资源上传" ;
            // 查询 资源上传 需要赠送的积分
            ScoreConfig scoreConfig = scoreConfigMapper.selectOne(new LambdaQueryWrapper<ScoreConfig>().eq(ScoreConfig::getAction, action));
            if (scoreConfig != null && scoreConfig.getScore() > 0) {
                // 准备赠送积分
                UserScore userScore = UserScore.builder()
                        .action(action)
                        .score(scoreConfig.getScore())
                        .resId(auditeDTO.getId())
                        .userId(resource.getUserId())
                        .build();
                // 插入 用户积分表中
                userScoreMapper.insert(userScore) ;
            }

            // 将资源信息拷贝到 ResourceViewVo 中
            ResourceViewVo resourceViewVo = new ResourceViewVo();
            BeanUtils.copyProperties(resource, resourceViewVo);
            // 将当前资源的访问量设置为 0，存储当 redis数据库中
            redisTemplate.opsForZSet().add(RedisConst.RESOURCE_VISIT_RANK_SET, resourceViewVo, 0) ;

            ResourceSolrDTO resourceSolrDTO = new ResourceSolrDTO() ;
            BeanUtils.copyProperties(resourceViewVo, resourceSolrDTO);
            resourceSolrDTO.setCreateTime(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(resource.getCreateTime()));
            // 将 审核通过 的资源， 存储到 solr 中，进行全文检索服务
            solrTemplate.saveBean(SolrConst.RESOURCE_SOLR_CORE, resourceSolrDTO) ;
            solrTemplate.commit(SolrConst.RESOURCE_SOLR_CORE);

        }
        // 发送 通知
        String text = MessageFormat.format("您上传的资源《{0}》因{1}原因，审核失败", resource.getResourceName(), auditeDTO.getReason());
        if (auditeDTO.getState() == 1) {
            text = MessageFormat.format("您上传的资源《{0}》已通过审核", resource.getResourceName());
        }

        Notify notify = Notify.builder()
                .typeName(NotifyType.AUDITE.getTypeName())
                .text(text)
                .resId(resource.getId())
                .userId(resource.getUserId())
                .build();

        // 将消息发送到 RssNotifyEvent 事件中
        applicationEventPublisher.publishEvent(new RssNotifyEvent(this, notify));

        return R.ok().build();
    }

    @Override
    public R<?> removeResource(Long resId) {
        // 先查询资源信息
        Resource resource = this.getBaseMapper().selectById(resId);

        Assert.notNull(resource, "资源信息找不到");

        int len = this.getBaseMapper().deleteById(resId);

        Assert.isTrue( len == 1, "下架资源失败");
        // 进行操作通知
        Notify notify = Notify.builder()
                .typeName(NotifyType.REMOVE.getTypeName())
                .resId(resId)
                .text(MessageFormat.format("您上传的资源《{0}》违反网站规则、已强制下架", resource.getResourceName()))
                .userId(resource.getUserId())
                .build();

        // 将消息发送到 RssNotifyEvent 事件中
        applicationEventPublisher.publishEvent(new RssNotifyEvent(this, notify));

        // 将该资源 从 solr 中移除
        solrTemplate.deleteByIds(SolrConst.RESOURCE_SOLR_CORE, String.valueOf(resId));
        solrTemplate.commit(SolrConst.RESOURCE_SOLR_CORE);

        return R.ok().build();
    }

    @Override
    public R<?> configCoreResource(Long resId) {
        // 先查询资源信息
        Resource resource = this.getBaseMapper().selectById(resId);

        Assert.notNull(resource, "资源信息找不到");

        int len = this.getBaseMapper().update(null,
                new UpdateWrapper<Resource>().set("core", !resource.getCore())
                        .set("update_time", LocalDateTime.now())
                        .eq("id", resId));

        Assert.isTrue( len == 1, "精选资源操作失败");

        String message = MessageFormat.format("您上传的资源《{0}》已设置为精选资源", resource.getResourceName());
        if (resource.getCore()) {
            message = MessageFormat.format("您上传的资源《{0}》已取消精选资源", resource.getResourceName());
        }
        // 进行操作通知
        Notify notify = Notify.builder()
                .typeName(NotifyType.CORE.getTypeName())
                .text(message)
                .userId(resource.getUserId())
                .resId(resId)
                .build();

        // 将消息发送到 RssNotifyEvent 事件中
        applicationEventPublisher.publishEvent(new RssNotifyEvent(this, notify));

        return R.ok().build();
    }
}




